﻿// ********************************
// 2010.11.24
// 拓扑解析
// Author:卢融凯
// ********************************
using System;
using System.Collections.Generic;
using SManage.Infrastructure;
using System.Drawing;
using System.Net;
using SManage.Model;
using System.Linq;

namespace SManage.Control
{
    static class TopologyParser
    {
        private static ICollection<ITopologyNode> tempNodeCollection = new List<ITopologyNode>();

        public static ITopologyNode Parse(Size size) {
            //var firstInfo = TopologyInfoAnalyst.GetFirstDeviceTopologyInfo();
            //if (firstInfo == null) {
            //    return null;
            //}
            //return Parse(firstInfo, size);

            return FindingTopology().AssignLocation(size);
        }

        public static ITopologyNode Parse(IPAddress ip, Size size) {
            //var info = TopologyInfoAnalyst.GetTopologyInfoFromIp(ip);
            //return Parse(info, size);

            return FindingTopology().AssignLocation(size);
        }

        public static ITopologyNode Parse(ITopologyInfo rootInfo, Size size) {
            tempNodeCollection.Clear();
            return Finding(rootInfo).AssignLocation(size);
        }

        /// <summary>
        /// Discovery core
        /// </summary>
        /// <param name="nodeInfo">Station node</param>
        /// <returns>Topology node</returns>
        private static ITopologyNode Finding(ITopologyInfo nodeInfo) {
            var current = nodeInfo.ToTopologyNode();
            tempNodeCollection.Add(current);

            foreach (var route in nodeInfo.IpRoutes) {
                Boolean pass = false;
                foreach (var nc in tempNodeCollection) {
                    if (nc.InterfaceList.Contains(route.Next)) {
                        current.LinkList.Add(nc);
                        //nc.LinkList.Add(current);
                        pass = true;
                        break;
                    }
                }
                if (!pass) {
                    var nextInfo = TopologyInfoAnalyst.GetTopologyInfoFromIp(route.Next);
                    var newNode = Finding(nextInfo);
                    current.LinkList.Add(newNode);
                }
            }
            return current;
        }
        
        private static ITopologyNode FindingTopology() {
            ITopologyNode result = new TopologyNode();

            var infoCollection = new List<ITopologyInfo>();
            using (var sme = new SManageEntities()) {
                var devices = sme.Devices;
                foreach (var device in devices) {
                    device.Mib2_systemReference.Load();
                    device.Mib2_ipReference.Load();
                    device.Mib2_interfacesReference.Load();
                    device.Mib2_interfaces.Mib2_interfaces_ifEntry.Load();
                    device.Mib2_ip.Mib2_ip_ipAddrEntry.Load();
                    device.Mib2_ip.Mib2_ip_ipNetToMediaEntry.Load();
                    device.Mib2_ip.Mib2_ip_ipRouteEntry.Load();
                    var node = TopologyInfoAnalyst.GetTopolotyInfoFromDevice(device);
                    infoCollection.Add(node);
                }
            }

            result = ProcessInfoCollection(infoCollection);
            return result;
        }

        private static ITopologyNode ProcessInfoCollection(List<ITopologyInfo> infoCollection) {
            var dict = new Dictionary<ITopologyNode, ITopologyInfo>();
            foreach (var i in infoCollection) {
                var node = i.ToTopologyNode();
                if (node.Station.Type == StationType.Computer) {
                    continue;
                }
                dict.Add(node, i);
            }

            foreach (var ni in dict) {
                var node = ni.Key;
                tempNodeCollection.Add(node);
                //dict.Remove(node);
                foreach (var i in ni.Value.IpRoutes) {
                    var nexts = from n in dict.Keys
                                where n.InterfaceList.Contains(i.Next)
                                select n;
                    if (nexts.Count() > 0) {
                        node.LinkList.Add(nexts.First());
                    }
                }
                foreach (var m in ni.Value.IpNetToMedias) {
                    var nexts = from n in dict.Keys
                                where n.InterfaceList.Contains(m.IP)
                                select n;
                    if (nexts.Count() > 0) {
                        node.LinkList.Add(nexts.First());
                    }
                }
            }

            var core = from a in tempNodeCollection
                       orderby a.LinkList.Count()
                       select a;

            //ProcessLinks(tempNodeCollection);

            return core.First();
        }

        private static void ProcessLinks(ICollection<ITopologyNode> tempNodeCollection) {
            foreach(var n in tempNodeCollection) {
                if (n.Station.Type == StationType.Router) {
                    var pcCollection = new List<ITopologyNode>();
                    foreach(var l in n.LinkList) {
                        if(l.Station.Type == StationType.Computer) {
                            pcCollection.Add(l);
                        }
                    }
                    foreach (var pc in pcCollection) {
                        n.LinkList.Remove(pc);
                    }
                }
            }

            var pcs = from p in tempNodeCollection
                      where p.Station.Type == StationType.Computer
                      select p;

            foreach (var pc in pcs) {
                var switchs = (from s in tempNodeCollection
                              where s.Station.Type == StationType.Switch
                              where s.LinkList.Contains(pc)
                              select s).ToList();
                if (switchs.Count() > 1) {
                    for (int i = 0; i < switchs.Count(); i++) {
                        if (i == 0) {
                            continue;
                        }
                        switchs[i].LinkList.Remove(pc);
                    }
                }
            }
        }
    }
}
